/*********************************************************************************
 * 
 *      Copyright:  (C) 2025 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  getdata.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(30/04/25)
 *         Author:  chenhongyu0822@163.com
 *      ChangeLog:  1, Release initial version on "30/04/25 22:11:27"
 *                 
 ********************************************************************************
 ********************************************************************************/
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<dirent.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>

#include "logger.h"

#define       CRC16          0x1021
#define       TLV_HEADER     0xFEED
#define       TLV_MINSIZE    7
#define       RPI_LEN        8
#define       TEMP_LEN       4
#define       TIME_LEN       19
#define       TLV_VALUE_LEN  (RPI_LEN+TEMP_LEN+TIME_LEN)
#define       TLV_TOTAL_LEN  (TLV_MINSIZE+TLV_VALUE_LEN)

typedef struct {
      char     rpi[RPI_LEN+1];  
      float    temp;    
      char     time[TIME_LEN+1]; 
}Sample_Data_t;

int get_temperature(float *temp)
{
    int                           fd;
    char                          buf[128];
    char                          *ptr;
    DIR                           *dirp=NULL;
    struct dirent                 *direntp=NULL;
    char                          w1_path[64]="/sys/bus/w1/devices/";
    char                          serial_num[32];
    int                           found=0;
    char                          ds18b20_path[128];

    if (temp == NULL) 
	{
		log_error("Invalid argument: temp pointer is NULL\n");
		return -1;
	}
	dirp=opendir(w1_path);
    if(!dirp)
    {
		log_error("open folder %s failure:%s\n", w1_path, strerror(errno));
        return -2;
    }
	while(NULL!=(direntp=readdir(dirp)))
    {
        if(strstr(direntp->d_name, "28-")!=NULL)
        {
            strncpy(serial_num, direntp->d_name, sizeof(serial_num));
            found=1;
        }
    }
    closedir(dirp);

    if(!found)
    {
        log_error("can not find ds18b20 serial number\n");
        return -3;
    }

    snprintf(ds18b20_path, sizeof(ds18b20_path),
            "%s%s/w1_slave", w1_path, serial_num);

    fd=open(ds18b20_path, O_RDONLY);
    if(fd<0)
    {
		log_error("open file failure:%s\n", strerror(errno));
        return -4;
    }

    memset(buf, 0, sizeof(buf));
	if(read(fd, buf, sizeof(buf))<0)
    {
		log_error("read data from fd=%d failure:%s\n", fd, strerror(errno));
        close(fd);
		return -5;
    }

    ptr=strstr(buf, "t=");

    if(!ptr)
    {
		log_error("can not find t= string\n");
        close(fd);
		return -6;
    }

    ptr+=2;
    *temp=atof(ptr)/1000;

    close(fd);
    return 0;
}

void get_id(char *rpi_id, int size)
{
	char                          id[28]="RPI25001";

	strncpy(rpi_id, id, size);
	return;
}


void get_time(char *sample_time, int size)
{
	 time_t                        t;
     struct tm                     *timeinfo;

	 time(&t);
	 timeinfo=localtime(&t);
	 strftime(sample_time, size, "%Y-%m-%d|%H:%M:%S", timeinfo);
	 
	 return;
}

int segmented_pack(Sample_Data_t *pack_info, uint8_t *pack_buf, int size)
{
	 char              *buf=(char *)pack_buf;

	 if(!pack_info || !buf || size<0)
	 {
		 log_error("Invalid input argument!\n");
		 return -1;
	 }

	 memset(buf, 0, size);
     snprintf(buf, size, "rpi:%s--temp:%.2f--time:%s",pack_info->rpi, pack_info->temp, pack_info->time);

	 return strlen(buf);
}

int json_pack(Sample_Data_t *pack_info, uint8_t *pack_buf, int size)
{
	char              *buf=(char *)pack_buf;

    if(!pack_info || !buf || size<0)
    {
        log_error("Invalid input argument!\n");
        return -1;
    }
	
	memset(buf, 0, size);
	snprintf(buf, size, 
			"{\"rpi\":\"%s\", \"temp\":\"%.2f\", \"time\":\"%s\"}", 
			pack_info->rpi, pack_info->temp, pack_info->time);

	return strlen(buf);
}


uint16_t crc_t(const uint8_t *data, size_t length)
{
	uint16_t                   crc=0xFFFF;
	size_t                     i,j;

	for(i=0; i<length; i++)
	{
		crc^=((uint16_t)data[i]<<8);

		for(j=0; j<8; j++)
		{
			if(crc&0x8000)
			{
				crc=(crc << 1)^CRC16;
			}
			else
			{
				crc<<=1;
			}
		}
	}
	return crc;
}

uint16_t to_big_endian(uint16_t num)
{
	return (num<<8) | (num>>8);
}

int tlv_pack(Sample_Data_t *pack_info, uint8_t *  pack_buf, int size)
{
	int                    offset=0;
	uint16_t               crc;

	if(!pack_info||!pack_buf||size<TLV_TOTAL_LEN)
	{
		log_error("Invalid data argument!\n");
		return -1;
	}

	*(uint16_t *)pack_buf=to_big_endian(TLV_HEADER);
	offset += 2;

	pack_buf[offset++]=0x01;

	*(uint16_t *)(pack_buf + offset)=to_big_endian(TLV_VALUE_LEN);
	offset += 2;

	strncpy((char *)(pack_buf + offset), pack_info->rpi, RPI_LEN);
	offset += RPI_LEN;

	memcpy(pack_buf + offset, &pack_info->temp, TEMP_LEN);
	offset += TEMP_LEN;

	strncpy((char *)(pack_buf + offset), pack_info->time, TIME_LEN);
	offset += TIME_LEN;

	crc=crc_t(pack_buf, offset);
	*(uint16_t *)(pack_buf + offset)=crc;
	offset += 2;

	return offset;
}
